/**
 * \file la.h
 *
 * \brief Wrapper headers for BLAS/LAPACK.
 *
 * This program is free software under the GNU General Public License
 * (>=v2). Read the file COPYING that comes with GRASS for details.
 *
 * \author David D. Gray <ddgray AT armacde demon co uk>
 * \author GRASS GIS Development Team
 *
 * \date 2000-2007
 */

#ifndef LA_H_
#define LA_H_

/* QUESTION: On some systems there appears to be no default link
   to this. Do we create a symlink to
   /usr/lib/gcc-lib/<platform>/<vers_num>/include/g2c.h

   or link to any old f2c.h that happens to hanging around?

   A job for autoconf

   [Also a consideration for -lg2c]
*/

#include <grass/config.h>
#include <stdio.h>

#ifdef HAVE_G2C_H
#include <g2c.h>
#else /* for gcc4+ */
typedef int                       integer;
typedef unsigned int              uinteger;
typedef char *                    address;
typedef short                     shortint;
typedef float                     real;
typedef double                    doublereal;
typedef struct {real r, i;}       complex;
typedef struct {doublereal r, i;} doublecomplex;
typedef int                       logical;
typedef short                     shortlogical;
typedef char                      logical1;
typedef char                      integer1;
typedef long                      longint;
typedef unsigned long             ulongint;

/* IO stuff */
typedef int ftnlen;

/* procedure parameter types for -A */
typedef int          (*U_fp)();
typedef shortint     (*J_fp)();
typedef integer      (*I_fp)();
typedef real         (*R_fp)();
typedef doublereal   (*D_fp)(), (*E_fp)();
typedef void         (*C_fp)();
typedef void         (*Z_fp)();
typedef logical      (*L_fp)();
typedef shortlogical (*K_fp)();
typedef void         (*H_fp)();
typedef int          (*S_fp)();

/* E_fp is for real functions when -R is not specified */
typedef void       C_f;   /* complex function                    */
typedef void       H_f;   /* character function                  */
typedef void       Z_f;   /* double complex function             */
typedef doublereal E_f;   /* real function with -R not specified */
#endif /* HAVE_G2C_H */

/* The following may have to be selectively installed according
   to platform, at least partly
*/

#if defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK)
#include <grass/blas.h>
#include <grass/lapack.h>
#endif


/* Useful defines */

#define MAX_POS          1   /* Indicates maximum value         */
#define MAX_NEG         -1   /* Indicates minimum value         */
#define MAX_ABS          0   /* Indicates absolute value        */

#define DO_COMPACT       0   /* Elliminate unnecessary rows (cols) in matrix  */
#define NO_COMPACT       1   /* ... or not                                    */


/* define macros for fortran symbols (called directly). Needed because 
   of platform invariance on fortran->C symbol translations
*/

#if defined(HAVE_LIBBLAS) && defined(HAVE_LIBLAPACK)
#define f77_dgesv                   dgesv_
#define f77_dgemm                   dgemm_
#define f77_dnrm2                   dnrm2_
#endif

/* Operations should know type of coefficient matrix, so that
   they can call the right driver
*/

typedef enum { NONSYM, SYM, HERMITIAN } mat_type;
typedef enum { MATRIX_, ROWVEC_, COLVEC_ } mat_spec;
typedef enum { RVEC, CVEC }             vtype;


/************************************************************
 *                                                          *
 * A general matrix wrapper for use with BLAS / LAPACK      *
 *  routines, and perhaps elsewhere                         *
 *                                                          *
 ************************************************************/

typedef struct matrix_ {

  mat_spec type;    /* matrix, row vector or column vector? */
  int v_indx;       /* If a vector, which row(column) is active?
                     * If a matrix this is ignored. If value is < 0,
                     * the first row(column) is assumed, ie. index 0.  */
  int rows, cols;   /* Rows and columns of matrix */
  int ldim;         /* Lead dimension of matrix. How many `rows' are
                     * alloc'ed? May exceed real number of rows `rows' */
  doublereal *vals; /* The values (should be dimensioned to lda * cols */
  int is_init;      /* Is  matrix initialised: values array
                     * is allocated and parameters set ?               */
}  mat_struct;

typedef mat_struct vec_struct;


/* Prototypes */

/* Matrix routines corresponding to BLAS Level III */

mat_struct *G_matrix_init(int, int, int);
int G_matrix_zero(mat_struct *);
int G_matrix_set(mat_struct *, int, int, int);
mat_struct *G_matrix_copy(const mat_struct *);
mat_struct *G_matrix_add(mat_struct *, mat_struct *);
mat_struct *G_matrix_subtract(mat_struct *, mat_struct *);
mat_struct *G_matrix_scale(mat_struct *, const double);
mat_struct *G__matrix_add(mat_struct *, mat_struct *, const double, const double);
mat_struct *G_matrix_product(mat_struct *, mat_struct *);
mat_struct *G_matrix_transpose(mat_struct *);
int G_matrix_LU_solve(const mat_struct *, mat_struct **, const mat_struct *, mat_type);
mat_struct *G_matrix_inverse(mat_struct *);
void G_matrix_free(mat_struct *);
void G_matrix_print(mat_struct *);
int G_matrix_set_element(mat_struct *, int, int, double);
double G_matrix_get_element(mat_struct *, int, int);


/* Matrix-vector routines corresponding to BLAS Level II */

vec_struct *G_matvect_get_column(mat_struct *, int);
vec_struct *G_matvect_get_row(mat_struct *, int);
int G_matvect_extract_vector( mat_struct *, vtype, int);
int G_matvect_retrieve_matrix(vec_struct *);


/* Vector routines corresponding to BLAS Level I */

vec_struct *G_vector_init(int, int, vtype);
int G_vector_set(vec_struct *, int, int, vtype, int);
double G_vector_norm_euclid(vec_struct *);
double G_vector_norm_maxval(vec_struct *, int);
vec_struct *G_vector_copy(const vec_struct *, int);

/* Matrix and vector routines corresponding to ?? */

void G_vector_free(vec_struct *);
vec_struct *G_vector_sub(vec_struct *, vec_struct *, vec_struct *);
double G_vector_norm1(vec_struct *);
int G_matrix_read(FILE *, mat_struct *);
int G_matrix_stdin(mat_struct *);
int G_matrix_eigen_sort(vec_struct *, mat_struct *);

#endif /* LA_H_ */
